#define _J_RED_C_
#include "red.h"

#include "vrijeme.h"
#include "sinkronizacija.h"

#include "pozivi_jezgre.h"
#include "liste.h"
#include "razno.h"
#include "ispis.h"

//redovi za sve potrebe
ZAUZMI(j_red_t, j_red, NAJ_RED);

void j_redovi_inicijaliziraj()
{
	int i;

	for (i = 0; i < NAJ_RED; i++) {
		j_red[i].red.prvi = NULL;
		j_red[i].red.zadnji = NULL;
		j_red[i].tip = 0;
		j_red[i].zast = 0;
	}
	
	//j_red[0] je rezerviran za aktivnu dretvu
	j_red[AKTIVNA].red.prvi = NULL;		//ne koristi se
	j_red[AKTIVNA].red.zadnji = NULL;	//ne koristi se
	j_red[AKTIVNA].tip = AKTIVNA;
	j_red[AKTIVNA].sort = SORT_PRP;
	j_red[AKTIVNA].pr = -1;
	OZNACI_ZAUZETO(j_red, 0);

	//j_red[1] je rezerviran za pripravne dretve
	j_red[PRIPRAVNA].red.prvi = NULL;	//ne koristi se
	j_red[PRIPRAVNA].red.zadnji = NULL;	//ne koristi se
	j_red[PRIPRAVNA].tip = PRIPRAVNA;
	j_red[PRIPRAVNA].sort = SORT_PRP;
	j_red[PRIPRAVNA].pr = -1;
	OZNACI_ZAUZETO(j_red, 1);
	
	j_inicijaliziraj_sinkronizaciju();
}

//trazi prvi slobodan red (za bilo koji red blokiranih dretvi)
int j_dohvati_red (uint8 tip, int8 sort, uint16 zast)
{
	int id;
	
	//mora biti "poznatog" tipa
	switch (tip) {
	case REDDRETVE:
	case REDALARMA:
	case REDUI:
	case SEMAFOR:
	case MONITOR:
	case REDUVJETA:
	case BARIJERA:
	case CITAJPISI:
	case DOGADJAJ:
		break;
	default:
		j_ispisi("Nepoznati tip reda!\n");
		return -1;
	}

	if (sort != SORT_PRP && sort != SORT_PRIO) {
		j_ispisi("Nepoznati nacin slaganja reda!\n");
		return -1;
	}

	id = DOHVATI(j_red);
	
	if (id != -1) {
		j_red[id].tip = tip;
		j_red[id].sort = sort;
		j_red[id].zast = zast;
		j_red[id].pr = -1;
	}
	else {
		j_ispisi("Nema slobodna opisnika za red!\n");
	}

	return id;
}

int j_obrisi_red (int id)
{
	int br;
	
	//pri brisanju ne diraj nista osim blokiranih dretvi!

	if (OBRISI(j_red, id) == -1) {
		j_ispisi("Krivi id reda ili red nije zauzet (%d)\n", id);
		return -1;
	}

	//ako ima blokiranih dretvi, otpusti ih
	br = j_propusti_iz_reda(id, ISTINA);

	return br; // > 0 ako je bilo dretvi koje su bile u redu
}


// interne j funkcije - ne provjeravam parametre!

//stavi na kraj reda (ili prema prioritetu, ako je takav red)
void j_stavi_u_red (int red, void *_opd, void *_koliko)
{
	vrijeme_t *koliko = _koliko;
	j_opisnikdretve_t *opd = _opd;
	
	if (opd == NULL)
		opd = j_aktivna_dretva();
	
	if (j_red[red].sort == SORT_PRP) {
		DODAJ_NA_KRAJ(&j_red[red].red, opd);
	}
	else {
		DODAJ_U_SORT_LISTU(&j_red[red].red, opd, USPOREDI_PRIO)
	}

	opd->red = red;

	//ceka samo ograniceno vrijeme?
	if (koliko)
		j_postavi_dretvin_alarm(opd, koliko);

	j_aktiviraj_prvu_pripravnu();
}

//pronadji i makni dretvu iz reda (npr. zato jer je 'nasilno' zavrsavamo)
int j_makni_iz_reda (int red, void *_opd)
{
	j_opisnikdretve_t *opd = _opd;
	bool nasao = MAKNI_IZ_LISTE(&j_red[red].red, opd);

	if (nasao) {
		//ako je uz dretvu vezan alarm - obrisi ga
		j_obrisi_dretvin_alarm(opd);

		return 0;
	}
	else {
		return -1; //nema opisnika u redu
	}
}

//prvu dretvu iz reda (ili sve) stavi u red pripravnih
int j_propusti_iz_reda (int red, bool sve)
{
	j_opisnikdretve_t *iduci, *prvi = j_red[red].red.prvi;
	int br = 0;

	while (prvi != NULL) {
		iduci = prvi->iduci;
		j_samo_stavi_u_pripravne(prvi);

		//ako je uz dretvu vezan alarm - obrisi ga
		j_obrisi_dretvin_alarm(prvi);

		prvi = iduci;
		br++;

		if (!sve)
			break;
	}

	j_red[red].red.prvi = prvi;

	j_aktiviraj_prvu_pripravnu(); //po potrebi azuriraj aktivnu
	
	return br; //koliko je dretvi propusteno
}

int j_provjeri_red(int id)
{
	if (id < PRVIRED || id >= NAJ_RED) { //0-aktivna, 1-pripravne
		j_ispisi("Krivi id reda (%d)\n", id);
		j_zaustavi_potpuno(__FILE__);
		return -1;
	}

	if (PROVJERI_SLOBODNO(j_red, id)) {
		j_ispisi("Red nije zauzet! (%d)\n", id);
		return -1;
	}
	
	return 0;
}

j_red_t *j_dohv_red(int id)
{
	if (j_provjeri_red(id))
		return NULL;
	else
		return &j_red[id];
}

int j_tip_reda (int id)
{
	if (id >= 0 && id < NAJ_RED)
		return j_red[id].tip;
	else
		return -1;
}